from datetime import timedelta, datetime
from typing import cast
from django.conf import settings
from django.utils import timezone
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
from django.contrib.auth import get_user_model
from django.db import transaction
from rest_framework.views import APIView
import traceback
from rest_framework import status
from .models import UserToken


TOKEN_TTL_SECONDS = getattr(settings, 'AUTH_TOKEN_TTL_SECONDS', 24 * 60 * 60)
User = get_user_model()


@method_decorator(csrf_exempt, name='dispatch')
class RegisterView(APIView):
    authentication_classes = []
    permission_classes = []

    @transaction.atomic
    def post(self, request):
        try:
            user_id = request.data.get('id')
            password = request.data.get('password')
            missing = [k for k in ['password', 'id'] if not request.data.get(k)]
            if missing:
                return JsonResponse({
                    'code': 400,
                    'msg': '参数缺失',
                    'error': f"Missing required fields: {', '.join(missing)}",
                }, status=status.HTTP_400_BAD_REQUEST)

            if User.objects.filter(id=user_id).exists():
                return JsonResponse({
                    'code': 409,
                    'msg': '用户已存在',
                    'error': f"User with id '{user_id}' already exists",
                }, status=status.HTTP_409_CONFLICT)

            user = User.objects.create_user(id=user_id, password=password)
            # 注册成功后自动登录：生成并返回 token
            UserToken.objects.filter(user=user).delete()
            now = timezone.now()
            token_value = UserToken.generate_token_value(user.password, now)
            UserToken.objects.create(user=user, token=token_value, created_at=now)
            return JsonResponse({
                'code': 200,
                'msg': '注册成功，已自动登录',
                'data': {
                    'user_id': user.id,
                    'token': token_value,
                }
            }, status=status.HTTP_200_OK)
        except Exception as e:
            return JsonResponse({
                'code': 500,
                'msg': '注册失败，请稍后再试',
                'error': f"{e.__class__.__name__}: {e}",
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


def _extract_token_from_request(request):
    auth = request.headers.get('Authorization') or ''
    if auth.startswith('Token '):
        return auth[6:]
    token = request.data.get('token') if isinstance(request.data, dict) else None
    if token:
        return token
    return None


def _is_token_expired(token_obj: UserToken) -> bool:
    created_at = cast(datetime, token_obj.created_at)
    return timezone.now() - created_at > timedelta(seconds=TOKEN_TTL_SECONDS)


@method_decorator(csrf_exempt, name='dispatch')
class LoginView(APIView):
    authentication_classes = []
    permission_classes = []

    @transaction.atomic
    def post(self, request):
        try:
            user_id = request.data.get('id')
            password = request.data.get('password')
            if not user_id or not password:
                return JsonResponse({
                    'code': 401,
                    'msg': 'id或密码为空',
                    'error': 'id or password is empty',
                }, status=status.HTTP_401_UNAUTHORIZED) 

            try:
                user = User.objects.get(id=user_id)
            except User.DoesNotExist:
                return JsonResponse({
                    'code': 401,
                    'msg': 'id不存在',
                    'error': 'id not exists',
                }, status=status.HTTP_401_UNAUTHORIZED)

            if not user.check_password(password):
                return JsonResponse({
                    'code': 401,
                    'msg': '密码错误',
                    'error': 'password is incorrect',
                }, status=status.HTTP_401_UNAUTHORIZED)

            # 生成新token（先清理旧token）
            UserToken.objects.filter(user=user).delete()
            now = timezone.now()
            token_value = UserToken.generate_token_value(user.password, now)
            UserToken.objects.create(user=user, token=token_value, created_at=now)
            return JsonResponse({
                'code': 200,
                'msg': '登录成功',
                'data': {
                    'user_id': user.id,
                    'token': token_value,
                }
            }, status=status.HTTP_200_OK)
        except Exception as e:
            payload = {
                'code': 500,
                'msg': '登录失败，请稍后再试',
                'error': 'login failed, please try again later',
                'error_type': str(type(e)),
                'error_message': str(e),
            }
            if settings.DEBUG:
                payload['error_trace'] = traceback.format_exc()
            return JsonResponse(payload, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


@method_decorator(csrf_exempt, name='dispatch')
class LogoutView(APIView):
    authentication_classes = []
    permission_classes = []

    @transaction.atomic
    def post(self, request):
        token_value = _extract_token_from_request(request)
        if not token_value:
            return JsonResponse({
                'code': 401,
                'msg': '未提供token',
                'error': 'token is not provided',
            }, status=status.HTTP_401_UNAUTHORIZED)
        deleted = UserToken.objects.filter(token=token_value).delete()[0]
        if deleted:
            return JsonResponse({
                'code': 200,
                'msg': '已登出',
            }, status=status.HTTP_200_OK)
        return JsonResponse({
            'code': 400,
            'msg': 'token无效',
            'error': 'token is invalid',
        }, status=status.HTTP_400_BAD_REQUEST)


class AuthMixin:
    def get_user_by_token(self, request):
        token_value = _extract_token_from_request(request)
        if not token_value:
            return None
        try:
            token_obj = UserToken.objects.select_related('user').get(token=token_value)
        except UserToken.DoesNotExist:
            return None
        if _is_token_expired(token_obj):
            # 过期即销毁
            token_obj.delete()
            return None
        return token_obj.user
